out_x, out_y);
}
-/* Given a mouse NSEvent, returns the window in which the pointer
- * position from the event is. The returned coordinates are relative
- * to the found window, and normal GDK coordinates, not Quartz.
- */
+/* Given a mouse NSEvent (must be a mouse event for a GDK window),
+ * finds the subwindow over which the pointer is located. Returns
+ * coordinates relative to the found window. If no window is found,
+ * returns NULL.
+*/
static GdkWindow *
-find_window_for_mouse_ns_event (NSEvent *nsevent,
+find_mouse_window_for_ns_event (NSEvent *nsevent,
gint *x_ret,
gint *y_ret)
{
- NSWindow *nswindow;
- GdkWindow *toplevel;
+ GdkWindow *event_toplevel;
+ GdkWindow *mouse_toplevel;
+ GdkWindow *mouse_window;
NSPoint point;
gint x_tmp, y_tmp;
- GdkWindow *found_window;
-
- nswindow = [nsevent window];
- toplevel = [(GdkQuartzView *)[nswindow contentView] gdkWindow];
+ event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
point = [nsevent locationInWindow];
x_tmp = point.x;
/* Flip the y coordinate. */
- if (toplevel == _gdk_root)
+ if (event_toplevel == _gdk_root)
y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
else
{
GdkWindowImplQuartz *impl;
- impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (toplevel)->impl);
+ impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
y_tmp = impl->height - point.y;
}
- found_window = _gdk_quartz_window_find_child (toplevel, x_tmp, y_tmp);
+ if (!current_mouse_window)
+ return NULL;
+
+ mouse_toplevel = gdk_window_get_toplevel (current_mouse_window);
- /* Translate the coordinates so they are relative to the found
- * window.
- */
- if (found_window)
- get_child_coordinates_from_ancestor (toplevel,
+ get_converted_window_coordinates (event_toplevel,
+ x_tmp, y_tmp,
+ mouse_toplevel,
+ &x_tmp, &y_tmp);
+
+ mouse_window = _gdk_quartz_window_find_child (mouse_toplevel, x_tmp, y_tmp);
+ if (!mouse_window)
+ {
+ /* This happens for events on the window title and window
+ * buttons (and the desktop).
+ */
+ return NULL;
+ }
+
+ if (mouse_window != mouse_toplevel)
+ get_child_coordinates_from_ancestor (mouse_toplevel,
x_tmp, y_tmp,
- found_window,
+ mouse_window,
&x_tmp, &y_tmp);
*x_ret = x_tmp;
*y_ret = y_tmp;
- return found_window;
+ return mouse_window;
}
/* This function finds the correct window to send an event to, taking
{
GdkWindow *mouse_window;
- mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
+ mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
- if (!mouse_window)
- mouse_window = _gdk_root;
+ /* We don't need to handle the case where we don't find a mouse
+ * window (i.e. after leaving a gdk toplevel and not entering a
+ * new one) here, it's covered by NSMouseExited events.
+ */
+ if (mouse_window && mouse_window != current_mouse_window)
+ synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
- if (_gdk_quartz_pointer_grab_window)
- {
- if (mouse_window != current_mouse_window)
- synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
- }
- else
- {
- if (current_mouse_window != mouse_window)
- {
- synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
- _gdk_quartz_events_update_cursor (mouse_window);
- }
- }
+ /* FIXME: Does this check really work as intended? It seems like
+ * we sometimes get a cursor update when we shouldn't, for
+ * example during an implicit grab on a GtkButton, and dragging
+ * the mouse over a link button.
+ */
+ if (mouse_window && !_gdk_quartz_pointer_grab_window)
+ _gdk_quartz_events_update_cursor (mouse_window);
}
switch (event_type)
{
if (pointer_grab_owner_events)
{
- mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
+ mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
event_mask = get_event_mask_from_ns_event (nsevent);
real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
else
{
/* The non-grabbed case. */
- mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
+ mouse_window = find_mouse_window_for_ns_event (nsevent, x, y);
event_mask = get_event_mask_from_ns_event (nsevent);
real_window = find_window_interested_in_event_mask (mouse_window, event_mask, TRUE);
case NSMouseEntered:
{
- GdkWindow *mouse_window;
+ GdkWindow *event_toplevel;
+ GdkWindow *mouse_window;
+ NSPoint point;
+ gint x_tmp, y_tmp;
+
+ event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
+ point = [nsevent locationInWindow];
+
+ x_tmp = point.x;
+
+ /* Flip the y coordinate. */
+ if (event_toplevel == _gdk_root)
+ y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
+ else
+ {
+ GdkWindowImplQuartz *impl;
+
+ impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
+ y_tmp = impl->height - point.y;
+ }
+
+ /* This is the only case where we actually use the window from
+ * the event since we need to know which toplevel we entered
+ * so it can be tracked properly.
+ */
+ mouse_window = _gdk_quartz_window_find_child (event_toplevel, x_tmp, y_tmp);
+
+ /* Treat unknown windows (including title bar/buttons,
+ * desktop) as the root.
+ */
+ if (!mouse_window)
+ mouse_window = _gdk_root;
- mouse_window = find_window_for_mouse_ns_event (nsevent, x, y);
synthesize_crossing_events (mouse_window, GDK_CROSSING_NORMAL, nsevent, *x, *y);
}
break;
case NSMouseExited:
- synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, *x, *y);
+ {
+ GdkWindow *event_toplevel;
+ GdkWindow *mouse_window;
+ NSPoint point;
+ gint x_tmp, y_tmp;
+ gint x_orig, y_orig;
+
+ /* We get mouse exited when leaving toplevels. We only use
+ * this when leaving from a window to the root window. The
+ * other case is handled above by checking the motion/button
+ * events, or getting a MouseEntered for another GDK window.
+ *
+ * The reason we don't use MouseExited for other windows is
+ * that quartz first delivers the entered event and then the
+ * exited which is the opposite from what we need.
+ */
+
+ /* Check if the root window has a child at this position, if
+ * so ignore the event.
+ */
+ event_toplevel = [(GdkQuartzView *)[[nsevent window] contentView] gdkWindow];
+ point = [nsevent locationInWindow];
+
+ x_tmp = point.x;
+
+ /* Flip the y coordinate. */
+ if (event_toplevel == _gdk_root)
+ y_tmp = _gdk_quartz_window_get_inverted_screen_y (point.y);
+ else
+ {
+ GdkWindowImplQuartz *impl;
+
+ impl = GDK_WINDOW_IMPL_QUARTZ (GDK_WINDOW_OBJECT (event_toplevel)->impl);
+ y_tmp = impl->height - point.y;
+ }
+
+ if (gdk_window_get_origin (event_toplevel, &x_orig, &y_orig))
+ {
+ x_tmp += x_orig;
+ y_tmp += y_orig;
+ }
+
+ mouse_window = _gdk_quartz_window_find_child (_gdk_root, x_tmp, y_tmp);
+ if (mouse_window == _gdk_root)
+ synthesize_crossing_events (_gdk_root, GDK_CROSSING_NORMAL, nsevent, *x, *y);
+ }
break;
case NSKeyDown: